package com.example.nio;

import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NIOEchoServer {

    public static void main(String[] args) throws Exception {
        // 为了性能问题及响应时间，设置固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        // NIO基于Channel控制，所以有Selector管理所有的Channel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 设置为非阻塞模式
        serverSocketChannel.configureBlocking(false);
        // 设置监听端口
        serverSocketChannel.bind(new InetSocketAddress(HostInfo.PORT));
        // 设置Selector管理所有Channel
        Selector selector = Selector.open();
        // 注册并设置连接时处理
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务启动成功，监听端口为：" + HostInfo.PORT);
        // NIO使用轮询，当有请求连接时，则启动一个线程
        int keySelect = 0;
        while ((keySelect = selector.select()) > 0) {  // selector.select() 会阻塞到这里，当有客户端连接时才会向下走
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey next = iterator.next();
                if (next.isAcceptable()) { //  如果是连接的
                    SocketChannel accept = serverSocketChannel.accept();
                    if (accept != null) {
                        // 启动一个线程放入线程池，进行读取当前客户端发送的消息，并且又把这个消息回传回去
                        executorService.submit(new EchoClientHandle(accept));
                    }
                    iterator.remove();
                }
            }
        }
        System.out.println("---");
        executorService.shutdown();
        serverSocketChannel.close();
    }
}